package io.github.junxworks.qt.modules.strategy.ws;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.DefaultSessionKey;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;

import io.github.junxworks.ep.auth.model.UserModel;
import io.github.junxworks.ep.core.Result;

public abstract class SpringWebSocketHandler extends TextWebSocketHandler {

	private Logger log = LoggerFactory.getLogger(SpringWebSocketHandler.class);

	//在线总数
	protected static AtomicLong onlineCount = new AtomicLong(0);

	protected Map<Long, WebSocketSession> webSocketMap = Maps.newConcurrentMap();

	private UserModel getUserInfoBySessionId(String sessionId) {
		UserModel result = null;
		try {
			Session se = SecurityUtils.getSecurityManager().getSession(new DefaultSessionKey(sessionId));
			Object obj = se.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
			SimplePrincipalCollection coll = (SimplePrincipalCollection) obj;
			result = (UserModel) coll.getPrimaryPrincipal();
		} catch (UnknownSessionException e) {
			log.error("There is no session with id [{}]", sessionId);
		}
		return result;
	}

	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		String token = session.getHandshakeHeaders().get("_ht_").get(0);
		UserModel user = getUserInfoBySessionId(token);
		if (user == null) {
			sendMsg(session, "请先登录");
		}
		Long userId = user.getId();
		if (webSocketMap.containsKey(userId)) {
			WebSocketSession ss = webSocketMap.remove(userId);
			try {
				ss.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			webSocketMap.put(userId, session);
		} else {
			webSocketMap.put(userId, session);
			addOnlineCount();
		}
		log.info("[UserId:{}] 建立连接, 当前连接数:{}", String.valueOf(userId), getOnlineCount());
	}

	@Override
	public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
		// 处理接收到的消息
		String payload = message.getPayload().toString();
		Result res = handleMsg(payload);
		sendMsg(session, JSON.toJSONString(res));
	}

	abstract Result handleMsg(String msg);

	public static void sendMsg(WebSocketSession session, String msg) throws IOException {
		session.sendMessage(new TextMessage(msg));
	}

	@Override
	public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
		UserModel user = (UserModel) SecurityUtils.getSubject().getPrincipal();
		if (user != null) {
			Long userId = user.getId();
			log.error("[UserId:" + String.valueOf(userId) + "] websocket异常", exception);
		}
	}

	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		// 当连接关闭时
		// 可以在这里进行一些清理操作
		UserModel user = (UserModel) SecurityUtils.getSubject().getPrincipal();
		if (user != null) {
			Long userId = user.getId();
			if (webSocketMap.containsKey(userId)) {
				webSocketMap.remove(userId);
				subOnlineCount();
			}
			log.info("[UserId:{}] 断开连接 code:{} reason:{}, 当前连接数:{}", String.valueOf(userId), status.getCode(), status.getReason(), getOnlineCount());
		}
	}

	/**
	 * 获取当前连接数
	 *
	 * @return
	 */
	protected Long getOnlineCount() {
		return onlineCount.get();
	}

	/**
	 * 当前连接数加一
	 */
	protected Long addOnlineCount() {
		return onlineCount.incrementAndGet();
	}

	/**
	 * 当前连接数减一
	 */
	protected Long subOnlineCount() {
		return onlineCount.decrementAndGet();
	}
}